package com.crr.service.impl;

import com.crr.service.OrderService;
import com.crr.utils.RedisUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;

@Service
public class OrderServiceImpl2 implements OrderService {
    @Autowired
    RedisUtils redisUtils;

    @Override
    public int save(int userId, int goodsId) {

        String userKey="user:id:"+userId;
        //判断用户是否抢购过
        boolean flag=redisUtils.setNx(userKey,goodsId+"");
        if(!flag){
            //说明抢过了
            return 1;
        }


        String key = "goods:id:" + goodsId;
        //读redis 看看商品是否存在   如果不存在 查询数据库  缓存起来

        Object tmp=redisUtils.hget(key,"stock");

        while(null==tmp){
            //缓存 没有  查询数据库
            //不能直接查询 （如果直接查询，在高并发情况下，所有的请求都会直接查询数据库  造成数据库压力大..）
            //尝试获取查询数据库的权限 （锁）   获得锁  执行  失败  等待
            String lockKey="stockLock";
            boolean rs=redisUtils.setNx(lockKey,"1",5);
            System.out.println(userId+"尝试获取锁："+rs);
            if(rs){
                //获得锁  查询数据库 将数据放到redis里
                System.out.println(userId+" 请求查询数据库");
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
                test();
                //释放锁
                redisUtils.del(lockKey);
            }else{
                //没有获得锁 等待
                try {
                    System.out.println(userId+"没有抢到锁，等待中");
                    Thread.sleep(50);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            //重新读取内存
            tmp=redisUtils.hget(key,"stock");
        }






        //尝试扣减库存
        List<String> keys=new ArrayList<>();
        keys.add(key);
        keys.add("stock");
        Long stock = redisUtils.eval(getLua(),keys);
        if(stock==0){
            System.out.println(userId+"抢购失败:"+stock);
            return 0;//抢购失败
        }

        System.out.println("用户" + userId + "抢购第" + stock  + "台成功");
        //记录当前用户抢购成功
        redisUtils.set(userKey,goodsId);
        return 1;//返回抢购成功
    }

    /**
     *
     * @return  -1 代表没有库存  如果有 代表扣减后的库存
     */
    String getLua() {
        StringBuilder lua = new StringBuilder();
        lua.append("    local stock = tonumber(redis.call('hget', KEYS[1], KEYS[2]));");
        lua.append("    if (stock == 0) then");
        lua.append("        return 0;");
        lua.append("    end;");
        lua.append("    if (stock > 0) then");
        lua.append("        redis.call('HINCRBY', KEYS[1],KEYS[2], -1);");
        lua.append("        return stock;");
        lua.append("    end;");
        return lua.toString();
    }


    @Override
    public void test() {
        String key = "goods:id:1";
        redisUtils.hset(key, "name", "小米");
        redisUtils.hset(key, "stock", "1");
        redisUtils.hset(key, "price", "1999");
        redisUtils.set("stock","1");
    }
}